﻿///////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2023, ООО 1С-Софт
// Все права защищены. Эта программа и сопроводительные материалы предоставляются 
// в соответствии с условиями лицензии Attribution 4.0 International (CC BY 4.0)
// Текст лицензии доступен по ссылке:
// https://creativecommons.org/licenses/by/4.0/legalcode
///////////////////////////////////////////////////////////////////////////////////////////////////////

#Область СлужебныйПрограммныйИнтерфейс

// Поставляемые компоненты.
// 
// Возвращаемое значение:
//  Массив - идентификаторы поставляемых компонент
//
Функция ПоставляемыеКомпоненты() Экспорт

	ИспользуемыеВнешниеКомпоненты = ИспользуемыеВнешниеКомпоненты();
	Возврат ИспользуемыеВнешниеКомпоненты.ВыгрузитьКолонку("Идентификатор");
		
КонецФункции

// Представление компоненты для журнала регистрации
//
Функция ПредставлениеКомпоненты(Идентификатор, Версия) Экспорт

	Если ЗначениеЗаполнено(Версия) Тогда
		ПредставлениеКомпоненты = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = '%1 (версии %2)'"), Идентификатор, Версия);
	Иначе
		ПредставлениеКомпоненты = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = '%1 (последней версии)'"), Идентификатор);
	КонецЕсли;

	Возврат ПредставлениеКомпоненты;

КонецФункции

// Проверят доступна ли загрузка внешних компонент с портала.
//
// Возвращаемое значение:
//  Булево - признак доступности.
//
Функция ДоступнаЗагрузкаСПортала() Экспорт

	Если ОбщегоНазначения.ПодсистемаСуществует("ИнтернетПоддержкаПользователей.ПолучениеВнешнихКомпонент") Тогда
		МодульПолучениеВнешнихКомпонент = ОбщегоНазначения.ОбщийМодуль("ПолучениеВнешнихКомпонент");
		Возврат МодульПолучениеВнешнихКомпонент.ДоступнаЗагрузкаВнешнихКомпонент();
	КонецЕсли;

	Возврат Ложь;

КонецФункции

// Возвращает информацию о компоненте из файла внешней компоненты.
//
// Параметры:
//  ДвоичныеДанные - ДвоичныеДанные - двоичные данные файла компоненты.
//  ВыполнятьРазборИнфоФайла - Булево - требуется ли дополнительно анализировать
//          данные файла INFO.XML, если он есть.
//  ПараметрыПоискаДополнительнойИнформации - см. ВнешниеКомпонентыКлиент.ПараметрыЗагрузки.
//
// Возвращаемое значение:
//  Структура:
//      * Разобрано - Булево - Истина, если информация о компоненте успешно извлечена.
//      * Реквизиты - см. РеквизитыКомпоненты
//      * ДвоичныеДанные - ДвоичныеДанные - выгрузка файла компоненты.
//      * ДополнительнаяИнформация - Соответствие - информация, полученная по переданным параметрам поиска.
//      * ОписаниеОшибки - Строка - текст ошибки в случае, если Разобрано = Ложь.
//      * ИнформацияОбОшибке - ИнформацияОбОшибке, Неопределено - в случае исключения, если Разобрано = Ложь.
//      * ЭтоФайлСервиса - Булево - файл компонент загружен с портала ИТС для интерактивной загрузки.
//
Функция ИнформацияОКомпонентеИзФайла(ДвоичныеДанные, ВыполнятьРазборИнфоФайла = Истина,
	Знач ПараметрыПоискаДополнительнойИнформации = Неопределено) Экспорт

	Результат = Новый Структура;
	Результат.Вставить("Разобрано", Ложь);
	Результат.Вставить("Реквизиты", Новый Структура);
	Результат.Вставить("ДвоичныеДанные", Неопределено);
	Результат.Вставить("ДополнительнаяИнформация", Новый Соответствие);
	Результат.Вставить("ОписаниеОшибки", "");
	Результат.Вставить("ИнформацияОбОшибке", Неопределено);
	Результат.Вставить("ЭтоФайлСервиса", Ложь);
	
	Реквизиты = РеквизитыКомпоненты();
	Если ПараметрыПоискаДополнительнойИнформации = Неопределено Тогда
		ПараметрыПоискаДополнительнойИнформации = Новый Соответствие;
	КонецЕсли;
	ДополнительнаяИнформация = Новый Соответствие;
	НайденМанифест = Ложь;

	Попытка
		Поток = ДвоичныеДанные.ОткрытьПотокДляЧтения();
		ЧтениеАрхива = Новый ЧтениеZipФайла(Поток);
	Исключение
		Результат.ОписаниеОшибки = НСтр("ru = 'В файле отсутствует информация о компоненте.'");
		Возврат Результат;
	КонецПопытки;

	ВременныйКаталог = ФайловаяСистема.СоздатьВременныйКаталог("ExtComp");
	Для Каждого ЭлементАрхива Из ЧтениеАрхива.Элементы Цикл

		Если ЭлементАрхива.Зашифрован Тогда

			// Очищаем временные файлы и освобождаем память.
			ФайловаяСистема.УдалитьВременныйКаталог(ВременныйКаталог);
			ЧтениеАрхива.Закрыть();
			Поток.Закрыть();

			Результат.ОписаниеОшибки = НСтр("ru = 'ZIP-архив не должен быть зашифрован.'");
			Возврат Результат;

		КонецЕсли;

		Попытка
			
			ИсходноеПолноеИмя = НРег(ЭлементАрхива.ИсходноеПолноеИмя);

			Если ИсходноеПолноеИмя = "external-components.json" Тогда
				Результат.ЭтоФайлСервиса = Истина;
				Результат.ОписаниеОшибки = НСтр("ru = 'Это файл для загрузки компонент с Портала 1С:ИТС.'");
				Возврат Результат;
			КонецЕсли;
			
			// Поиск и разбор манифеста.
			Если ИсходноеПолноеИмя = "manifest.xml" Тогда

				Реквизиты.ДатаВерсии = ЭлементАрхива.ВремяИзменения;

				ЧтениеАрхива.Извлечь(ЭлементАрхива, ВременныйКаталог);
				ФайлManifestXML = ВременныйКаталог + ПолучитьРазделительПути() + ЭлементАрхива.ПолноеИмя;
				ЗаполнитьРеквизитыПоManifestXML(ФайлManifestXML, Реквизиты.ЦелевыеПлатформы);

				НайденМанифест = Истина;

			КонецЕсли;

			Если ИсходноеПолноеИмя = "info.xml" И ВыполнятьРазборИнфоФайла Тогда

				ЧтениеАрхива.Извлечь(ЭлементАрхива, ВременныйКаталог);
				ФайлInfoXML = ВременныйКаталог + ПолучитьРазделительПути() + ЭлементАрхива.ПолноеИмя;
				ЗаполнитьРеквизитыПоInfoXML(ФайлInfoXML, Реквизиты);

			КонецЕсли;

			Для Каждого ПараметрПоиска Из ПараметрыПоискаДополнительнойИнформации Цикл

				ИмяФайлаXML = ПараметрПоиска.Значение.ИмяФайлаXML;

				Если ИсходноеПолноеИмя = НРег(ИмяФайлаXML) Тогда

					КлючДополнительнойИнформации = ПараметрПоиска.Ключ;
					ВыражениеXPath = ПараметрПоиска.Значение.ВыражениеXPath;

					ЧтениеАрхива.Извлечь(ЭлементАрхива, ВременныйКаталог);
					ФайлManifestXML = ВременныйКаталог + ПолучитьРазделительПути() + ЭлементАрхива.ПолноеИмя;

					ДокументDOM = ДокументDOM(ФайлManifestXML);
					ЗначениеXPath = ВычислитьВыражениеXPath(ВыражениеXPath, ДокументDOM);

					ДополнительнаяИнформация.Вставить(КлючДополнительнойИнформации, ЗначениеXPath);

				КонецЕсли;

			КонецЦикла;

		Исключение
			Результат.ОписаниеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Некорректный файл %1'"), ЭлементАрхива.ИсходноеПолноеИмя);
			Результат.ИнформацияОбОшибке = ИнформацияОбОшибке();
			Возврат Результат;
		КонецПопытки;
	КонецЦикла;

	// Очищаем временные файлы и освобождаем память.
	ФайловаяСистема.УдалитьВременныйКаталог(ВременныйКаталог);
	ЧтениеАрхива.Закрыть();
	Поток.Закрыть();

	// Контроль соответствия компоненты.
	Если Не НайденМанифест Тогда
		ТекстОшибки = НСтр("ru = 'В архиве компоненты отсутствует обязательный файл MANIFEST.XML.'");

		Результат.ОписаниеОшибки = ТекстОшибки;
		Возврат Результат;
	КонецЕсли;

	Результат.Разобрано = Истина;
	Результат.Реквизиты = Реквизиты;
	Результат.ДвоичныеДанные = ДвоичныеДанные;
	Результат.ДополнительнаяИнформация = ДополнительнаяИнформация;

	Возврат Результат;

КонецФункции

Процедура ПроверитьМестоположениеКомпоненты(Идентификатор, Местоположение) Экспорт

	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РаботаВМоделиСервиса.ВнешниеКомпонентыВМоделиСервиса") Тогда
		МодульВнешниеКомпонентыВМоделиСервисаСлужебный = ОбщегоНазначения.ОбщийМодуль("ВнешниеКомпонентыВМоделиСервисаСлужебный");
		Если МодульВнешниеКомпонентыВМоделиСервисаСлужебный.ЭтоКомпонентаИзХранилища(Местоположение) Тогда
			Возврат;
		КонецЕсли;
	КонецЕсли;

	// В модели сервиса небезопасно подключать внешние компоненты на сервере 1С:Предприятие 
	// из справочника "Внешние компоненты" (допустимо только из справочника "Общие внешние компоненты").
	Если Не (ОбщегоНазначения.РазделениеВключено()
			И ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных()) Тогда
		Если Не СтрНачинаетсяС(Местоположение, "e1cib/data/Справочник.ВнешниеКомпоненты.ХранилищеКомпоненты") Тогда
			Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РаботаВМоделиСервиса.ВнешниеКомпонентыВМоделиСервиса") Тогда
				ТекстИсключения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Не удалось подключить компоненту ""%1"" по причине:
					|Доступ запрещен. Обратитесь к администратору сервиса, чтобы разместить внешнюю компоненту в справочник ""Общие внешние компоненты"".'"), Идентификатор);
			Иначе
				ТекстИсключения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Не удалось подключить компоненту ""%1"" по причине:
					|Доступ запрещен.'"), Идентификатор);
				КонецЕсли;
			ВызватьИсключение ТекстИсключения;
		КонецЕсли;
	КонецЕсли;

	Если СтрНачинаетсяС(Местоположение, "e1cib/data/Справочник.ВнешниеКомпоненты.ХранилищеКомпоненты") Тогда
		Возврат;
	КонецЕсли;

	ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Не удалось подключить компоненту ""%1"" по причине:
		|Недопустимое местоположение компоненты ""%2"".'"), Идентификатор, Местоположение);

КонецПроцедуры

// Параметры загрузки.
// 
// Возвращаемое значение:
//  Структура:
//   * Идентификатор - Строка
//   * Наименование - Строка
//   * Версия - Строка
//   * ИмяФайла - Строка
//   * ОписаниеОшибки - Строка - информация о загрузке компоненты
//   * ОбновлятьСПортала1СИТС - Булево
//   * Данные - Строка - адрес двоичных данных во временном хранилище 
//          - ДвоичныеДанные
//
Функция ПараметрыЗагрузки() Экспорт
	
	Результат = Новый Структура;
	Результат.Вставить("Идентификатор", "");
	Результат.Вставить("Наименование", "");
	Результат.Вставить("Версия", "");
	Результат.Вставить("ИмяФайла", "");
	Результат.Вставить("ОписаниеОшибки", "");
	Результат.Вставить("ОбновлятьСПортала1СИТС", Истина);
	Результат.Вставить("Данные", "");
	
	Возврат Результат;
	
КонецФункции

// Добавить компоненту в справочник из двоичных данных.
// 
// Параметры:
//  Параметры - см. ПараметрыЗагрузки
//  ВыполнятьРазборИнфоФайла - Булево - требуется ли дополнительно анализировать
//          данные файла INFO.XML, если он есть
//  ИспользуемыеВнешниеКомпоненты - см. ИспользуемыеВнешниеКомпоненты
//
Процедура ЗагрузитьКомпонентуИзДвоичныхДанных(Параметры, ВыполнятьРазборИнфоФайла = Истина, ИспользуемыеВнешниеКомпоненты = Неопределено) Экспорт
	
	Если ТипЗнч(Параметры.Данные) = Тип("Строка") Тогда
		Если ПустаяСтрока(Параметры.Данные) Тогда
			ТекстИсключения = НСтр("ru = 'Не заполнены данные.'");
			ВызватьИсключение ТекстИсключения;
		Иначе
			Если ЭтоАдресВременногоХранилища(Параметры.Данные) Тогда
				ДвоичныеДанные = ПолучитьИзВременногоХранилища(Параметры.Данные);
			Иначе
				ВызватьИсключение НСтр("ru = 'Адрес данных не является адресом временного хранилища.'");
			КонецЕсли;
		КонецЕсли;
	Иначе
		ДвоичныеДанные = Параметры.Данные;
	КонецЕсли;
	
	Если ТипЗнч(ДвоичныеДанные) <> Тип("ДвоичныеДанные") Тогда
		ТекстИсключения =  НСтр("ru = 'Данные файла не являются двоичными данными.'");
		ВызватьИсключение ТекстИсключения;
	КонецЕсли;
	
	Информация = ИнформацияОКомпонентеИзФайла(ДвоичныеДанные, ВыполнятьРазборИнфоФайла);

	Если Не Информация.Разобрано Тогда
		
		ТекстИсключения = Информация.ОписаниеОшибки + ?(Информация.ИнформацияОбОшибке = Неопределено, "",
			 ": " + ОбработкаОшибок.КраткоеПредставлениеОшибки(Информация.ИнформацияОбОшибке));
		
		ЗаписьЖурналаРегистрации(НСтр("ru = 'Добавление внешней компоненты'", ОбщегоНазначения.КодОсновногоЯзыка()),
			УровеньЖурналаРегистрации.Ошибка, , , ТекстИсключения);
		ВызватьИсключение ТекстИсключения;
	КонецЕсли;
	
	Идентификатор = ?(ЗначениеЗаполнено(Параметры.Идентификатор), Параметры.Идентификатор, Информация.Реквизиты.Идентификатор);
	
	Если Не ЗначениеЗаполнено(Идентификатор) Тогда
		ТекстИсключения = НСтр("ru = 'Не указан идентификатор, необходимо ввести его вручную.'");
		ВызватьИсключение ТекстИсключения;
	КонецЕсли;
	
	НачатьТранзакцию();
	Попытка

		Блокировка = Новый БлокировкаДанных;
		Блокировка.Добавить("Справочник.ВнешниеКомпоненты");
		Блокировка.Заблокировать();

		Компонента = Справочники.ВнешниеКомпоненты.НайтиПоИдентификатору(Идентификатор);

		Если ЗначениеЗаполнено(Компонента) Тогда
			Объект = Компонента.ПолучитьОбъект();
			Попытка
				РезультатСравненияВерсий = ОбщегоНазначенияКлиентСервер.СравнитьВерсии(Объект.Версия, Параметры.Версия);
			Исключение
				// Если не удалось сравнить версии, перезаписываем компоненту.
				РезультатСравненияВерсий = -1;
			КонецПопытки;
			Если РезультатСравненияВерсий >= 0 Тогда
				ОтменитьТранзакцию();
				Возврат;
			КонецЕсли;
		Иначе
			Объект = Справочники.ВнешниеКомпоненты.СоздатьЭлемент();
			// Создание экземпляра компоненты.
			Объект.Заполнить(Неопределено); // Конструктор по умолчанию.
		КонецЕсли;
		
		 // По данным манифеста.
		ЗаполнитьЗначенияСвойств(Объект, Информация.Реквизиты, , "Наименование, Версия, ИмяФайла");
		
		Объект.Идентификатор = Идентификатор;
		// Если в параметрах Наименование, Версия, ИмяФайла не заполнены, берем из информации.
		Объект.Наименование = ?(ЗначениеЗаполнено(Параметры.Наименование), Параметры.Наименование, Информация.Реквизиты.Наименование);
		Объект.Версия = ?(ЗначениеЗаполнено(Параметры.Версия), Параметры.Версия, Информация.Реквизиты.Версия);
		Объект.ИмяФайла = ?(ЗначениеЗаполнено(Параметры.ИмяФайла), Параметры.ИмяФайла, Информация.Реквизиты.ИмяФайла);
		Объект.ОписаниеОшибки = Параметры.ОписаниеОшибки;
		Объект.ОбновлятьСПортала1СИТС = Параметры.ОбновлятьСПортала1СИТС;
		Объект.ЦелевыеПлатформы = Новый ХранилищеЗначения(Информация.Реквизиты.ЦелевыеПлатформы);
		
		Если ИспользуемыеВнешниеКомпоненты <> Неопределено Тогда
			СтрокаКомпоненты = ИспользуемыеВнешниеКомпоненты.Найти(Идентификатор, "Идентификатор");
			Если СтрокаКомпоненты <> Неопределено Тогда
				Объект.ОбновлятьСПортала1СИТС = СтрокаКомпоненты.ОбновлятьАвтоматически;
			КонецЕсли;
		КонецЕсли;
		
		Объект.ДополнительныеСвойства.Вставить("ДвоичныеДанныеКомпоненты", Информация.ДвоичныеДанные);
		
		Объект.Записать();
		
		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
		ЗаписьЖурналаРегистрации(НСтр("ru = 'Добавление внешней компоненты'", ОбщегоНазначения.КодОсновногоЯзыка()), 
			УровеньЖурналаРегистрации.Ошибка, , , ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
		ВызватьИсключение;
	КонецПопытки;
	
КонецПроцедуры


#Область ОбработчикиСобытийПодсистемКонфигурации

// См. ГрупповоеИзменениеОбъектовПереопределяемый.ПриОпределенииОбъектовСРедактируемымиРеквизитами.
Процедура ПриОпределенииОбъектовСРедактируемымиРеквизитами(Объекты) Экспорт

	Объекты.Вставить(Метаданные.Справочники.ВнешниеКомпоненты.ПолноеИмя(), "РеквизитыРедактируемыеВГрупповойОбработке");

КонецПроцедуры

// См. ВыгрузкаЗагрузкаДанныхПереопределяемый.ПриЗаполненииТиповИсключаемыхИзВыгрузкиЗагрузки.
Процедура ПриЗаполненииТиповИсключаемыхИзВыгрузкиЗагрузки(Типы) Экспорт

	МодульВыгрузкаЗагрузкаДанных = ОбщегоНазначения.ОбщийМодуль("ВыгрузкаЗагрузкаДанных");
	МодульВыгрузкаЗагрузкаДанных.ДополнитьТипомИсключаемымИзВыгрузкиЗагрузки(Типы,
		Метаданные.Справочники.ВнешниеКомпоненты,
		МодульВыгрузкаЗагрузкаДанных.ДействиеСоСсылкамиОчищать());

КонецПроцедуры

// См. СтандартныеПодсистемыСервер.ПриОтправкеДанныхГлавному.
Процедура ПриОтправкеДанныхГлавному(ЭлементДанных, ОтправкаЭлемента,
		Получатель) Экспорт

	Если ТипЗнч(ЭлементДанных) = Тип("СправочникОбъект.ВнешниеКомпоненты") Тогда
		ОтправкаЭлемента = ОтправкаЭлементаДанных.Игнорировать;
	КонецЕсли;

КонецПроцедуры

// См. СтандартныеПодсистемыСервер.ПриОтправкеДанныхПодчиненному.
Процедура ПриОтправкеДанныхПодчиненному(ЭлементДанных, ОтправкаЭлемента,
		СозданиеНачальногоОбраза, Получатель) Экспорт

	Если ТипЗнч(ЭлементДанных) = Тип("СправочникОбъект.ВнешниеКомпоненты") Тогда
		ОтправкаЭлемента = ОтправкаЭлементаДанных.Игнорировать;
	КонецЕсли;

КонецПроцедуры

// См. СтандартныеПодсистемыСервер.ПриПолученииДанныхОтГлавного.
Процедура ПриПолученииДанныхОтГлавного(ЭлементДанных, ПолучениеЭлемента,
		ОтправкаНазад, Отправитель) Экспорт

	Если ТипЗнч(ЭлементДанных) = Тип("СправочникОбъект.ВнешниеКомпоненты") Тогда
		ПолучениеЭлемента = ПолучениеЭлементаДанных.Игнорировать;
	КонецЕсли;

КонецПроцедуры

// См. СтандартныеПодсистемыСервер.ПриПолученииДанныхОтПодчиненного.
Процедура ПриПолученииДанныхОтПодчиненного(ЭлементДанных, ПолучениеЭлемента,
		ОтправкаНазад, Отправитель) Экспорт

	Если ТипЗнч(ЭлементДанных) = Тип("СправочникОбъект.ВнешниеКомпоненты") Тогда
		ПолучениеЭлемента = ПолучениеЭлементаДанных.Игнорировать;
	КонецЕсли;

КонецПроцедуры

// См. ОбщегоНазначенияПереопределяемый.ПриДобавленииСерверныхОповещений
Процедура ПриДобавленииСерверныхОповещений(Оповещения) Экспорт
	
	Оповещение = СерверныеОповещения.НовоеСерверноеОповещение(
		"СтандартныеПодсистемы.ВнешниеКомпоненты");
	
	Оповещение.ИмяМодуляОтправки  = "ВнешниеКомпонентыСлужебный";
	Оповещение.ИмяМодуляПолучения = "ВнешниеКомпонентыСлужебныйКлиент";
	
	Оповещения.Вставить(Оповещение.Имя, Оповещение);
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Обработчики событий подсистемы ТекущиеДела.

// Параметры:
//   ТекущиеДела - см. ТекущиеДелаСервер.ТекущиеДела.
//
Процедура ПриЗаполненииСпискаТекущихДел(ТекущиеДела) Экспорт
	
	Если Пользователи.ЭтоСеансВнешнегоПользователя() Или Не Пользователи.ЭтоПолноправныйПользователь() Тогда
		Возврат;
	КонецЕсли;

	МодульТекущиеДелаСервер = ОбщегоНазначения.ОбщийМодуль("ТекущиеДелаСервер");
	Разделы = МодульТекущиеДелаСервер.РазделыДляОбъекта(Метаданные.Справочники.ВнешниеКомпоненты.ПолноеИмя());

	КоличествоНеиспользуемыхКомпонент = КоличествоНеиспользуемыхКомпонент();
	Для Каждого Раздел Из Разделы Цикл
		Дело = ТекущиеДела.Добавить ();
		Дело.Идентификатор  = "УдалитьНеиспользуемыеКомпоненты";
		Дело.ЕстьДела       = КоличествоНеиспользуемыхКомпонент > 0;
		Дело.Представление  = НСтр("ru = 'Удалить неиспользуемые компоненты'");
		Дело.Количество     = КоличествоНеиспользуемыхКомпонент;
		Дело.Важное         = Ложь;
		Дело.Форма          = "Справочник.ВнешниеКомпоненты.ФормаСписка";
		Дело.ПараметрыФормы = Новый Структура("ИспользованиеОтбор", 3);
		Дело.Владелец       = Раздел;
	КонецЦикла;

КонецПроцедуры

#КонецОбласти

// См. ОбновлениеИнформационнойБазыБСП.ПриДобавленииОбработчиковОбновления.
Процедура ПриДобавленииОбработчиковОбновления(Обработчики) Экспорт
	
	Обработчик = Обработчики.Добавить();
	Обработчик.Версия = "3.1.9.226";
	Обработчик.Идентификатор = Новый УникальныйИдентификатор("664e552f-4552-4eb2-970b-d63f66cc1c71");
	Обработчик.Процедура = "Справочники.ВнешниеКомпоненты.ОбработатьДанныеДляПереходаНаНовуюВерсию";
	Обработчик.НачальноеЗаполнение = Истина;
	Обработчик.Комментарий = НСтр("ru = 'Заполнение реквизитов совместимости компонент и добавление стандартных компонент в справочник Внешние компоненты.'");
	Обработчик.РежимВыполнения = "Отложенно";
	Обработчик.ПроцедураЗаполненияДанныхОбновления = "Справочники.ВнешниеКомпоненты.ЗарегистрироватьДанныеКОбработкеДляПереходаНаНовуюВерсию";
	Обработчик.ЧитаемыеОбъекты      = "Справочник.ВнешниеКомпоненты";
	Обработчик.ИзменяемыеОбъекты    = "Справочник.ВнешниеКомпоненты";
	
КонецПроцедуры

#КонецОбласти

#Область СлужебныеПроцедурыИФункции

// Внешние компоненты, используемые в конфигурации.
// 
// Возвращаемое значение:
//  ТаблицаЗначений:
//   * Идентификатор - Строка
//   * ОбновлятьАвтоматически - Булево 
//
Функция ИспользуемыеВнешниеКомпоненты() Экспорт
	
	ИспользуемыеВнешниеКомпоненты = Новый ТаблицаЗначений;
	ИспользуемыеВнешниеКомпоненты.Колонки.Добавить("Идентификатор",          ОбщегоНазначения.ОписаниеТипаСтрока(50));
	ИспользуемыеВнешниеКомпоненты.Колонки.Добавить("ОбновлятьАвтоматически", Новый ОписаниеТипов("Булево"));
	
	ИнтеграцияПодсистемБСП.ПриОпределенииИспользуемыхВнешнихКомпонент(ИспользуемыеВнешниеКомпоненты);
	
	Возврат ИспользуемыеВнешниеКомпоненты;
	
КонецФункции

// Проверят доступна ли интерактивная загрузка внешних компонент с портала.
//
// Возвращаемое значение:
//  Булево - признак доступности.
//
Функция ДоступнаИнтерактивнаяЗагрузкаСПортала() Экспорт

	Если ОбщегоНазначения.ПодсистемаСуществует("ИнтернетПоддержкаПользователей") 
		И ОбщегоНазначения.ПодсистемаСуществует("ИнтернетПоддержкаПользователей.ПолучениеВнешнихКомпонент") Тогда
		МодульИнтернетПоддержкаПользователейКлиентСервер = ОбщегоНазначения.ОбщийМодуль("ИнтернетПоддержкаПользователейКлиентСервер");
		Если ОбщегоНазначенияКлиентСервер.СравнитьВерсии(
			МодульИнтернетПоддержкаПользователейКлиентСервер.ВерсияБиблиотеки(), "2.7.2.0") >= 0 Тогда
			МодульПолучениеВнешнихКомпонент = ОбщегоНазначения.ОбщийМодуль("ПолучениеВнешнихКомпонент");
			Возврат МодульПолучениеВнешнихКомпонент.ДоступнаЗагрузкаВнешнихКомпонент();
		КонецЕсли;
	КонецЕсли;

	Возврат Ложь;

КонецФункции

// Возвращает таблицу описаний внешних компонент
//
// Параметры:
//  Вариант - Строка - может принимать значения:
//    "ДляОбновления" - компоненты только из справочника с установленным признаком ОбновлятьСПортала1СИТС.
//    "ДляЗагрузки"   - компоненты, используемые в конфигурации.
//
// Возвращаемое значение:
//   ТаблицаЗначений:
//    * Идентификатор - Строка
//    * Версия - Строка
//    * Наименование - Строка
//    * ДатаВерсии - Дата
//    * ОбновлятьАвтоматически - Булево
//
Функция ДанныеВнешнихКомпонент(Вариант = "ДляОбновления") Экспорт
	
	Запрос = Новый Запрос;
	
	Если Вариант = "ДляОбновления" Тогда
		Запрос.Текст = 
			"ВЫБРАТЬ
			|	ВнешниеКомпоненты.Идентификатор КАК Идентификатор,
			|	ВнешниеКомпоненты.Версия КАК Версия,
			|	ВнешниеКомпоненты.Наименование КАК Наименование,
			|	ВнешниеКомпоненты.ДатаВерсии КАК ДатаВерсии,
			|	ВнешниеКомпоненты.ОбновлятьСПортала1СИТС КАК ОбновлятьАвтоматически
			|ИЗ
			|	Справочник.ВнешниеКомпоненты КАК ВнешниеКомпоненты
			|ГДЕ
			|	ВнешниеКомпоненты.ОбновлятьСПортала1СИТС";
			
	ИначеЕсли Вариант = "ДляЗагрузки" Тогда
		
		Запрос.Текст =
			"ВЫБРАТЬ
			|	ИспользуемыеВнешниеКомпоненты.Идентификатор,
			|	ИспользуемыеВнешниеКомпоненты.ОбновлятьАвтоматически
			|ПОМЕСТИТЬ ИспользуемыеВнешниеКомпоненты
			|ИЗ
			|	&ИспользуемыеВнешниеКомпоненты КАК ИспользуемыеВнешниеКомпоненты
			|;
			|
			|////////////////////////////////////////////////////////////////////////////////
			|ВЫБРАТЬ
			|	ЕСТЬNULL(ВнешниеКомпоненты.Идентификатор, ИспользуемыеВнешниеКомпоненты.Идентификатор) КАК Идентификатор,
			|	ЕСТЬNULL(ВнешниеКомпоненты.Версия, """") КАК Версия,
			|	ЕСТЬNULL(ВнешниеКомпоненты.Наименование, """") КАК Наименование,
			|	ЕСТЬNULL(ВнешниеКомпоненты.ДатаВерсии, ДатаВремя(1, 1, 1)) КАК ДатаВерсии,
			|	ЕСТЬNULL(ВнешниеКомпоненты.ОбновлятьСПортала1СИТС, ИспользуемыеВнешниеКомпоненты.ОбновлятьАвтоматически) КАК
			|		ОбновлятьАвтоматически
			|ИЗ
			|	Справочник.ВнешниеКомпоненты КАК ВнешниеКомпоненты
			|		ПОЛНОЕ СОЕДИНЕНИЕ ИспользуемыеВнешниеКомпоненты КАК ИспользуемыеВнешниеКомпоненты
			|		ПО ВнешниеКомпоненты.Идентификатор = ИспользуемыеВнешниеКомпоненты.Идентификатор";
			
			Запрос.УстановитьПараметр("ИспользуемыеВнешниеКомпоненты", ИспользуемыеВнешниеКомпоненты());
	Иначе
		ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Неизвестный параметр ""%1"" в ""%2"".'"), Вариант,
			"ВнешниеКомпонентыСлужебный.ДанныеВнешнихКомпонент");
	КонецЕсли;
	
	РезультатЗапроса = Запрос.Выполнить();
	ОписаниеВнешнихКомпонент = РезультатЗапроса.Выгрузить();
	
	Возврат ОписаниеВнешнихКомпонент;

КонецФункции

Процедура УдалитьНеиспользуемыеКомпоненты() Экспорт
	
	Запрос = Новый Запрос;
	Запрос.Текст =
	"ВЫБРАТЬ
	|	ВнешниеКомпоненты.Ссылка КАК Ссылка
	|ИЗ
	|	Справочник.ВнешниеКомпоненты КАК ВнешниеКомпоненты
	|ГДЕ
	|	НЕ ВнешниеКомпоненты.ПометкаУдаления
	|	И НЕ ВнешниеКомпоненты.Идентификатор В (&Идентификаторы)";

	Запрос.УстановитьПараметр("Идентификаторы", ПоставляемыеКомпоненты());

	Выборка = Запрос.Выполнить().Выбрать();
	Пока Выборка.Следующий() Цикл

		НачатьТранзакцию();
		Попытка
			Блокировка = Новый БлокировкаДанных;
			ЭлементБлокировки = Блокировка.Добавить("Справочник.ВнешниеКомпоненты");
			ЭлементБлокировки.УстановитьЗначение("Ссылка", Выборка.Ссылка);
			Блокировка.Заблокировать();

			Объект = Выборка.Ссылка.ПолучитьОбъект();
			Объект.ПометкаУдаления = Истина;
			Объект.Записать();
			ЗафиксироватьТранзакцию();
		Исключение
			ОтменитьТранзакцию();
			ЗаписьЖурналаРегистрации(НСтр("ru = 'Удаление внешней компоненты'", ОбщегоНазначения.КодОсновногоЯзыка()),
				УровеньЖурналаРегистрации.Ошибка, , , ОбработкаОшибок.ПодробноеПредставлениеОшибки(
				ИнформацияОбОшибке()));
			ВызватьИсключение;
		КонецПопытки;
		
	КонецЦикла;
	
	ОповеститьВсеСеансыОбИзмененииВнешнейКомпоненты();
	
КонецПроцедуры

Функция КоличествоНеиспользуемыхКомпонент()
	
	КоличествоНеиспользуемыхКомпонент = 0;
	
	Запрос = Новый Запрос;
	Запрос.Текст = 
			"ВЫБРАТЬ
			|	КОЛИЧЕСТВО(ВнешниеКомпоненты.Ссылка) КАК КоличествоНеиспользуемыхКомпонент
			|ИЗ
			|	Справочник.ВнешниеКомпоненты КАК ВнешниеКомпоненты
			|ГДЕ
			|	НЕ ВнешниеКомпоненты.ПометкаУдаления
			|	И НЕ ВнешниеКомпоненты.Идентификатор В (&Идентификаторы)";
	
	Запрос.УстановитьПараметр("Идентификаторы", ПоставляемыеКомпоненты());
		
	Выборка = Запрос.Выполнить().Выбрать();
	Пока Выборка.Следующий() Цикл
		Возврат Выборка.КоличествоНеиспользуемыхКомпонент;
	КонецЦикла;
	
	Возврат КоличествоНеиспользуемыхКомпонент;
	
КонецФункции

Процедура ОповеститьВсеСеансыОбИзмененииВнешнейКомпоненты() Экспорт
	
	СерверныеОповещения.ОтправитьСерверноеОповещение(
		"СтандартныеПодсистемы.ВнешниеКомпоненты", "", Неопределено, Истина);
	
КонецПроцедуры

// См. СтандартныеПодсистемыСервер.ПриОтправкеСерверногоОповещения
Процедура ПриОтправкеСерверногоОповещения(ИмяОповещения, ВариантыПараметров) Экспорт
	
	Если ИмяОповещения <> "СтандартныеПодсистемы.ВнешниеКомпоненты" Тогда
		Возврат;
	КонецЕсли;
	
	ИмяПараметра = "СтандартныеПодсистемы.ВнешниеКомпоненты.Версии";
	СтароеЗначение = СтандартныеПодсистемыСервер.ПараметрРаботыРасширения(ИмяПараметра, Истина);
	НовоеЗначение = ХешСуммаВерсийВнешнихКомпонент();
	
	Если СтароеЗначение = НовоеЗначение Тогда
		Возврат;
	КонецЕсли;
	
	СерверныеОповещения.ОтправитьСерверноеОповещение(ИмяОповещения, "", Неопределено);
	
	Блокировка = Новый БлокировкаДанных;
	ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ПараметрыРаботыВерсийРасширений");
	ЭлементБлокировки.УстановитьЗначение("ВерсияРасширений", Справочники.ВерсииРасширений.ПустаяСсылка());
	ЭлементБлокировки.УстановитьЗначение("ИмяПараметра", ИмяПараметра);
	
	НачатьТранзакцию();
	Попытка
		Блокировка.Заблокировать();
		СтароеЗначение = СтандартныеПодсистемыСервер.ПараметрРаботыРасширения(ИмяПараметра, Истина);
		Если СтароеЗначение <> НовоеЗначение Тогда
			СтандартныеПодсистемыСервер.УстановитьПараметрРаботыРасширения(ИмяПараметра, НовоеЗначение, Истина);
		КонецЕсли;
		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
		ВызватьИсключение;
	КонецПопытки;
	
КонецПроцедуры

Функция ХешСуммаВерсийВнешнихКомпонент()
	
	Запрос = Новый Запрос;
	Запрос.Текст =
	"ВЫБРАТЬ
	|	ВнешниеКомпоненты.Ссылка КАК Ссылка,
	|	ВнешниеКомпоненты.ВерсияДанных КАК ВерсияДанных
	|ИЗ
	|	Справочник.ВнешниеКомпоненты КАК ВнешниеКомпоненты";
	
	Выборка = Запрос.Выполнить().Выбрать();
	
	СписокВерсий = Новый СписокЗначений;
	ДобавитьВерсииКомпонент(СписокВерсий, Выборка);
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РаботаВМоделиСервиса.ВнешниеКомпонентыВМоделиСервиса") Тогда
		МодульВнешниеКомпонентыВМоделиСервисаСлужебный = ОбщегоНазначения.ОбщийМодуль("ВнешниеКомпонентыВМоделиСервисаСлужебный");
		Выборка = МодульВнешниеКомпонентыВМоделиСервисаСлужебный.ВерсииОбщихВнешнихКомпонент();
		ДобавитьВерсииКомпонент(СписокВерсий, Выборка);
	КонецЕсли;
	
	СписокВерсий.СортироватьПоЗначению();
	Версии = СтрСоединить(СписокВерсий.ВыгрузитьЗначения(), Символы.ПС);
	Хеширование = Новый ХешированиеДанных(ХешФункция.SHA256);
	Хеширование.Добавить(Версии);
	СтрокаХешСуммы = Base64Строка(Хеширование.ХешСумма);
	
	Возврат СтрокаХешСуммы;
	
КонецФункции

// Параметры:
//  СписокВерсий - СписокЗначений
//  Выборка - ВыборкаДанных:
//   * Ссылка - СправочникСсылка
//   * ВерсияДанных - Строка
//
Процедура ДобавитьВерсииКомпонент(СписокВерсий, Выборка)
	
	Пока Выборка.Следующий() Цикл
		СписокВерсий.Добавить(НРег(Выборка.Ссылка.УникальныйИдентификатор())
			+ " " + Выборка.ВерсияДанных);
	КонецЦикла;
	
КонецПроцедуры

// Проверяет возможность подключения на сервере 1С:Предприятия внешней компоненты из хранилища внешних компонент, 
// выполненной по технологии Native API или COM.
//
// Параметры:
//   Идентификатор - Строка - идентификатор объекта внешней компоненты.
//   Версия        - Строка - версия компоненты.
//   ПараметрыПодключения - см. ВнешниеКомпонентыСервер.ПараметрыПодключения.
//
// Возвращаемое значение:
//   Строка - краткое описание ошибки. 
//
Функция ПроверитьПодключениеКомпоненты(Знач Идентификатор,
		Знач Версия = Неопределено,
		Знач ПараметрыПодключения = Неопределено) Экспорт

	Если ПараметрыПодключения = Неопределено Тогда
		ПараметрыПодключения = ВнешниеКомпонентыСервер.ПараметрыПодключения();
	КонецЕсли;

	Если ПустаяСтрока(Идентификатор) Тогда
		КомпонентаСодержитЕдинственныйКлассОбъектов = (ПараметрыПодключения.ИдентификаторыСозданияОбъектов.Количество() = 0);
		Если КомпонентаСодержитЕдинственныйКлассОбъектов Тогда
			ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Недопустимо одновременно не указывать %1 и %2 при подключении внешней компоненты.'"),
				"Идентификатор", "ИдентификаторыСозданияОбъектов");
		КонецЕсли;
		Идентификатор = СтрСоединить(ПараметрыПодключения.ИдентификаторыСозданияОбъектов, ", ");
	КонецЕсли;

	Результат = Новый Структура;
	Результат.Вставить("Местоположение", "");
	Результат.Вставить("Идентификатор", Идентификатор);
	Результат.Вставить("ОписаниеОшибки", "");
	Результат.Вставить("Версия", "");

	Информация = ВнешниеКомпонентыСлужебныйВызовСервера.ИнформацияОСохраненнойКомпоненте(Идентификатор, Версия, ПараметрыПодключения.ПолноеИмяМакета);
	Результат.Вставить("Версия", Версия);
	Если Информация.Состояние = "ОтключенаАдминистратором" Тогда
		Результат.ОписаниеОшибки = НСтр("ru = 'Компонента отключена администратором.'");
		Возврат Результат;
	ИначеЕсли Информация.Состояние = "НеНайдена" Тогда
		Результат.ОписаниеОшибки = НСтр("ru = 'Компонента отсутствует в списке разрешенных внешних компонент.'");
		Возврат Результат;
	ИначеЕсли Информация.ЗаполненыЦелевыеПлатформы И Не ОперационнаяСистемаПоддерживаетсяКомпонентой(Информация.Реквизиты.ЦелевыеПлатформы) Тогда
		СистемнаяИнформация = Новый СистемнаяИнформация;
		Результат.ОписаниеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Не предусмотрена работа компоненты в операционной системе %1.'"), Строка(СистемнаяИнформация.ТипПлатформы));
		Возврат Результат;
	КонецЕсли;
	
	ПроверитьМестоположениеКомпоненты(Идентификатор, Информация.Местоположение);
	Результат.Местоположение = Информация.Местоположение;
	Возврат Результат;

КонецФункции

#Область ИнформацияОСохраненнойКомпоненте

Функция ОперационнаяСистемаПоддерживаетсяКомпонентой(РеквизитыКомпоненты)

	СистемнаяИнформация = Новый СистемнаяИнформация;
	
	ИмяТипаПлатформы = ОбщегоНазначенияКлиентСервер.ИмяТипаПлатформы(СистемнаяИнформация.ТипПлатформы);

	Если ИмяТипаПлатформы = "Linux_x86" Тогда
		Возврат РеквизитыКомпоненты.Linux_x86;
	ИначеЕсли ИмяТипаПлатформы = "Linux_x86_64" Тогда
		Возврат РеквизитыКомпоненты.Linux_x86_64;
	ИначеЕсли ИмяТипаПлатформы = "MacOS_x86" Тогда
		Возврат РеквизитыКомпоненты.MacOS_x86;
	ИначеЕсли ИмяТипаПлатформы = "MacOS_x86_64" Тогда
		Возврат РеквизитыКомпоненты.MacOS_x86_64;
	ИначеЕсли ИмяТипаПлатформы = "Windows_x86" Тогда
		Возврат РеквизитыКомпоненты.Windows_x86;
	ИначеЕсли ИмяТипаПлатформы = "Windows_x86_64" Тогда
		Возврат РеквизитыКомпоненты.Windows_x86_64;
	ИначеЕсли ИмяТипаПлатформы = "Linux_ARM64" Тогда
		Возврат РеквизитыКомпоненты.Linux_ARM64;
	ИначеЕсли ИмяТипаПлатформы = "Linux_E2K" Тогда
		Возврат РеквизитыКомпоненты.Linux_e2k;
	ИначеЕсли ИмяТипаПлатформы = "Android_ARM" Тогда
		Возврат РеквизитыКомпоненты.Android_ARM;
	ИначеЕсли ИмяТипаПлатформы = "Android_ARM_64" Тогда
		Возврат РеквизитыКомпоненты.Android_ARM64;
	ИначеЕсли ИмяТипаПлатформы = "Android_x86" Тогда
		Возврат РеквизитыКомпоненты.Android_x86;
	ИначеЕсли ИмяТипаПлатформы = "Android_x86_64" Тогда
		Возврат РеквизитыКомпоненты.Android_x86_64;
	ИначеЕсли ИмяТипаПлатформы = "iOS_ARM" Тогда
		Возврат РеквизитыКомпоненты.iOS_ARM;
	ИначеЕсли ИмяТипаПлатформы = "iOS_ARM_64" Тогда
		Возврат РеквизитыКомпоненты.iOS_ARM64;
	ИначеЕсли ИмяТипаПлатформы = "WinRT_ARM" Тогда
		Возврат РеквизитыКомпоненты.WindowsRT_ARM;
	ИначеЕсли ИмяТипаПлатформы = "WinRT_x86" Тогда
		Возврат РеквизитыКомпоненты.WindowsRT_x86;
	ИначеЕсли ИмяТипаПлатформы = "WinRT_x86_64" Тогда
		Возврат РеквизитыКомпоненты.WindowsRT_x86_64;
	КонецЕсли;

	Возврат Ложь;

КонецФункции

Функция ДоступнаЗагрузкаИзФайла()

	Возврат Пользователи.ЭтоПолноправныйПользователь(, , Ложь);

КонецФункции

// Параметры:
//   Идентификатор - Строка               - идентификатор объекта внешней компоненты.
//   Версия        - Строка
//                 - Неопределено - версия компоненты.
//   ПутьКМакетуДляПоискаПоследнейВерсии 
//                 - Неопределено
//                 - Строка
//
// Возвращаемое значение:
//  Структура:
//    * ДоступнаЗагрузкаСПортала - Булево
//    * ДоступнаЗагрузкаИзФайла - Булево
//    * Состояние - Строка - "НеНайдена", "НайденаВХранилище", "НайденаВОбщемХранилище", "ОтключенаАдминистратором" 
//    * Местоположение - Строка
//    * Ссылка - ЛюбаяСсылка
//    * Реквизиты - см. РеквизитыКомпоненты
//    * ЗаполненыЦелевыеПлатформы - Булево
//    * ПоследняяВерсияКомпонентыИзМакета 
//    		- см. СтандартныеПодсистемыПовтИсп.ПоследняяВерсияКомпонентыИзМакета
//    		- Неопределено
//
Функция ИнформацияОСохраненнойКомпоненте(Идентификатор, Версия = Неопределено, ПутьКМакетуДляПоискаПоследнейВерсии = Неопределено) Экспорт

	Результат = Новый Структура;
	Результат.Вставить("Ссылка");
	Результат.Вставить("Реквизиты", РеквизитыКомпоненты());
	Результат.Вставить("Местоположение");
	Результат.Вставить("Состояние");
	Результат.Вставить("ДоступнаЗагрузкаИзФайла", ДоступнаЗагрузкаИзФайла());
	Результат.Вставить("ДоступнаЗагрузкаСПортала", ДоступнаЗагрузкаСПортала());
	Результат.Вставить("ПоследняяВерсияКомпонентыИзМакета");
	Результат.Вставить("ЗаполненыЦелевыеПлатформы", Ложь);

	Если ОбщегоНазначения.РазделениеВключено()
		И ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РаботаВМоделиСервиса.ВнешниеКомпонентыВМоделиСервиса") Тогда
	
		МодульВнешниеКомпонентыВМоделиСервисаСлужебный = ОбщегоНазначения.ОбщийМодуль("ВнешниеКомпонентыВМоделиСервисаСлужебный");
		МодульВнешниеКомпонентыВМоделиСервисаСлужебный.ЗаполнитьИнформациюОКомпоненте(Результат, Версия, Идентификатор);
	Иначе	
		СсылкаИзХранилища = Справочники.ВнешниеКомпоненты.НайтиПоИдентификатору(Идентификатор, Версия);
		Если СсылкаИзХранилища.Пустая() Тогда
			Результат.Состояние = "НеНайдена";
		Иначе
			Результат.Состояние = "НайденаВХранилище";
			Результат.Ссылка = СсылкаИзХранилища;
		КонецЕсли
	КонецЕсли;
	
	Если ПутьКМакетуДляПоискаПоследнейВерсии <> Неопределено Тогда
		Результат.ПоследняяВерсияКомпонентыИзМакета = СтандартныеПодсистемыПовтИсп.ПоследняяВерсияКомпонентыИзМакета(
			ПутьКМакетуДляПоискаПоследнейВерсии);
	КонецЕсли;

	Если Результат.Состояние = "НеНайдена" Тогда
		Возврат Результат;
	КонецЕсли;

	Реквизиты = РеквизитыКомпоненты();
	Если Результат.Состояние = "НайденаВХранилище" Тогда
		Реквизиты.Вставить("Использование");
	КонецЕсли;
	Если Результат.Состояние = "НайденаВОбщемХранилище" Тогда
		Реквизиты.Удалить("ИмяФайла");
	КонецЕсли;
	Реквизиты.ЦелевыеПлатформы = Неопределено;
	
	РеквизитыОбъекта = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(Результат.Ссылка, Реквизиты);
	
	РеквизитыОбъекта.ЦелевыеПлатформы = РеквизитыОбъекта.ЦелевыеПлатформы.Получить();
	Если РеквизитыОбъекта.ЦелевыеПлатформы = Неопределено Тогда
		
		ТекстПредупреждения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Не заполнена информация о совместимости компоненты %1.'"), Идентификатор);
		ЗаписьЖурналаРегистрации(НСтр("ru = 'Проверка совместимости компоненты'",
			ОбщегоНазначения.КодОсновногоЯзыка()), УровеньЖурналаРегистрации.Предупреждение, , Результат.Ссылка, ТекстПредупреждения);
		
		РеквизитыОбъекта.ЦелевыеПлатформы = ЦелевыеПлатформы();
	Иначе
		Результат.ЗаполненыЦелевыеПлатформы = Истина;
	КонецЕсли;

	ЗаполнитьЗначенияСвойств(Результат.Реквизиты, РеквизитыОбъекта);
	Результат.Местоположение = ПолучитьНавигационнуюСсылку(Результат.Ссылка, "ХранилищеКомпоненты");

	Если Результат.Состояние = "НайденаВХранилище" Тогда
		Если РеквизитыОбъекта.Использование <> Перечисления.ВариантыИспользованияВнешнихКомпонент.Используется Тогда
			Результат.Состояние = "ОтключенаАдминистратором";
		КонецЕсли;
	КонецЕсли;
	
	Возврат Результат;

КонецФункции

// Возвращаемое значение:
//  Структура:
//    * ЦелевыеПлатформы - см. ЦелевыеПлатформы
//    * Идентификатор - Строка
//    * Наименование - Строка
//    * Версия - Строка
//    * ДатаВерсии - Дата
//    * ИмяФайла - Строка
//
Функция РеквизитыКомпоненты()

	Реквизиты = Новый Структура;
	Реквизиты.Вставить("Идентификатор");
	Реквизиты.Вставить("Наименование");
	Реквизиты.Вставить("Версия");
	Реквизиты.Вставить("ДатаВерсии");
	Реквизиты.Вставить("ИмяФайла");
	Реквизиты.Вставить("ЦелевыеПлатформы", ЦелевыеПлатформы());

	Возврат Реквизиты;

КонецФункции

// Возвращаемое значение:
//  Структура:
//    * Windows_x86 - Булево
//    * Windows_x86_64 - Булево
//    * Linux_x86 - Булево
//    * Linux_x86_64 - Булево
//    * Windows_x86_Firefox - Булево
//    * Linux_x86_Firefox - Булево
//    * Linux_x86_64_Firefox - Булево
//    * Windows_x86_MSIE - Булево
//    * Windows_x86_64_MSIE - Булево
//    * Windows_x86_Chrome - Булево
//    * Linux_x86_Chrome - Булево
//    * Linux_x86_64_Chrome - Булево
//    * MacOS_x86_64_Safari - Булево
//    * MacOS_x86_64_Chrome - Булево
//    * MacOS_x86_64_Firefox - Булево
//    * Windows_x86_ЯндексБраузер - Булево
//    * Windows_x86_64_ЯндексБраузер - Булево
//    * Linux_x86_ЯндексБраузер - Булево
//    * Linux_x86_64_ЯндексБраузер - Булево
//    * MacOS_x86_64_ЯндексБраузер - Булево
//    * Linux_E2K - Булево
//    * Linux_E2K_Firefox - Булево
//    * Linux_E2K_ЯндексБраузер - Булево
//    * Linux_E2K_Chrome - Булево
//    * Linux_ARM64 - Булево
//    * iOS_ARM - Булево
//    * iOS_ARM64 - Булево
//    * Android_ARM - Булево
//    * Android_x86_64 - Булево
//    * Android_x86 - Булево
//    * Android_ARM64 - Булево
//    * WindowsRT_ARM - Булево
//    * WindowsRT_x86 - Булево
//    * WindowsRT_x86_64 - Булево
//
Функция ЦелевыеПлатформы()

	Реквизиты = Новый Структура;
	Реквизиты.Вставить("Windows_x86",                  Ложь);
	Реквизиты.Вставить("Windows_x86_64",               Ложь);
	Реквизиты.Вставить("Linux_x86",                    Ложь);
	Реквизиты.Вставить("Linux_x86_64",                 Ложь);
	Реквизиты.Вставить("Windows_x86_Firefox",          Ложь);
	Реквизиты.Вставить("Linux_x86_Firefox",            Ложь);
	Реквизиты.Вставить("Linux_x86_64_Firefox",         Ложь);
	Реквизиты.Вставить("Windows_x86_MSIE",             Ложь);
	Реквизиты.Вставить("Windows_x86_64_MSIE",          Ложь);
	Реквизиты.Вставить("Windows_x86_Chrome",           Ложь);
	Реквизиты.Вставить("Linux_x86_Chrome",             Ложь);
	Реквизиты.Вставить("Linux_x86_64_Chrome",          Ложь);
	Реквизиты.Вставить("MacOS_x86_64",                 Ложь);
	Реквизиты.Вставить("MacOS_x86_64_Safari",          Ложь);
	Реквизиты.Вставить("MacOS_x86_64_Chrome",          Ложь);
	Реквизиты.Вставить("MacOS_x86_64_Firefox",         Ложь);
	Реквизиты.Вставить("Windows_x86_ЯндексБраузер",    Ложь);
	Реквизиты.Вставить("Windows_x86_64_ЯндексБраузер", Ложь);
	Реквизиты.Вставить("Linux_x86_ЯндексБраузер",      Ложь);
	Реквизиты.Вставить("Linux_x86_64_ЯндексБраузер",   Ложь);
	Реквизиты.Вставить("MacOS_x86_64_ЯндексБраузер",   Ложь);
	Реквизиты.Вставить("Linux_E2K",                    Ложь);
	Реквизиты.Вставить("Linux_E2K_Firefox",            Ложь);
	Реквизиты.Вставить("Linux_E2K_ЯндексБраузер",      Ложь);
	Реквизиты.Вставить("Linux_E2K_Chrome",             Ложь);
	Реквизиты.Вставить("Linux_ARM64",                  Ложь);
	Реквизиты.Вставить("Linux_ARM64_Firefox",          Ложь);
	Реквизиты.Вставить("Linux_ARM64_ЯндексБраузер",    Ложь);
	Реквизиты.Вставить("Linux_ARM64_Chrome",           Ложь);
	Реквизиты.Вставить("iOS_ARM",                      Ложь);
	Реквизиты.Вставить("iOS_ARM64",                    Ложь);
	Реквизиты.Вставить("Android_ARM",                  Ложь);
	Реквизиты.Вставить("Android_x86_64",               Ложь);
	Реквизиты.Вставить("Android_x86",                  Ложь);
	Реквизиты.Вставить("Android_ARM64",                Ложь);
	Реквизиты.Вставить("WindowsRT_ARM",                Ложь);
	Реквизиты.Вставить("WindowsRT_x86",                Ложь);
	Реквизиты.Вставить("WindowsRT_x86_64",             Ложь);
	
	Возврат Реквизиты;

КонецФункции

#КонецОбласти

#Область ПолучениеИнформацииИзФайлаКомпоненты

Процедура ЗаполнитьРеквизитыПоManifestXML(ИмяФайлаManifestXML, Реквизиты)

	ЧтениеXML = Новый ЧтениеXML;
	ЧтениеXML.ОткрытьФайл(ИмяФайлаManifestXML);

	ЧтениеXML.ПерейтиКСодержимому();
	Если ЧтениеXML.Имя = "bundle" И ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
		Пока ЧтениеXML.Прочитать() Цикл
			Если ЧтениеXML.Имя = "component" И ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда

				ОперационнаяСистема = НРег(ЧтениеXML.ЗначениеАтрибута("os"));
				ТипКомпоненты = НРег(ЧтениеXML.ЗначениеАтрибута("type"));
				АрхитектураПлатформы = НРег(ЧтениеXML.ЗначениеАтрибута("arch"));
				ПрограммаПросмотра = НРег(ЧтениеXML.ЗначениеАтрибута("client"));

				Если ОперационнаяСистема = "windows" И (ТипКомпоненты = "native" Или ТипКомпоненты = "com") Тогда

					Если АрхитектураПлатформы = "i386" Тогда
						Реквизиты.Windows_x86 = Истина;
						Продолжить;
					КонецЕсли;

					Если АрхитектураПлатформы = "x86_64" Тогда
						Реквизиты.Windows_x86_64 = Истина;
						Продолжить;
					КонецЕсли;
					
					Продолжить;
				КонецЕсли;
				
				Если ОперационнаяСистема = "linux" И ТипКомпоненты = "native" Тогда
				
					Если АрхитектураПлатформы = "i386" Тогда
						Реквизиты.Linux_x86 = Истина;
						Продолжить;
					КонецЕсли;
	
					Если АрхитектураПлатформы = "x86_64" Тогда
						Реквизиты.Linux_x86_64 = Истина;
						Продолжить;
					КонецЕсли;
					
					Если АрхитектураПлатформы = "arm64" Тогда
						Реквизиты.Linux_ARM64 = Истина;
						Продолжить;
					КонецЕсли;
					
					Если АрхитектураПлатформы = "e2k" Тогда
						Реквизиты.Linux_E2K = Истина;
						Продолжить;
					КонецЕсли;
					
					Продолжить;
				КонецЕсли;
				
				Если ОперационнаяСистема = "macos" И ТипКомпоненты = "native" И (АрхитектураПлатформы = "x86_64"
						Или АрхитектураПлатформы = "universal") Тогда
					Реквизиты.MacOS_x86_64 = Истина;
					Продолжить;
				КонецЕсли;
				
				Если ОперационнаяСистема = "windowsruntime" Тогда

					Если АрхитектураПлатформы = "arm" Тогда
						Реквизиты.WindowsRT_ARM = Истина;
					ИначеЕсли АрхитектураПлатформы = "x86_64" Тогда
						Реквизиты.WindowsRT_x86_64 = Истина;
					ИначеЕсли АрхитектураПлатформы = "x86" Тогда
						Реквизиты.WindowsRT_x86 = Истина;
					КонецЕсли;
					
					Продолжить;
					
				КонецЕсли;
				
				Если ОперационнаяСистема = "android" Тогда

					Если АрхитектураПлатформы = "arm" Тогда
						Реквизиты.Android_ARM = Истина;
					ИначеЕсли АрхитектураПлатформы = "arm64" Тогда
						Реквизиты.Android_ARM64 = Истина;
					ИначеЕсли АрхитектураПлатформы = "x86_64" Тогда
						Реквизиты.Android_x86_64 = Истина;
					ИначеЕсли АрхитектураПлатформы = "i386" Тогда
						Реквизиты.Android_x86 = Истина;
					КонецЕсли;
					
					Продолжить;
					
				КонецЕсли;
				
				Если ОперационнаяСистема = "ios" Тогда

					Если АрхитектураПлатформы = "arm" Или АрхитектураПлатформы = "universal" Тогда
						Реквизиты.iOS_ARM = Истина;
					КонецЕсли;
					
					Если АрхитектураПлатформы = "arm64" Или АрхитектураПлатформы = "universal" Тогда
						Реквизиты.iOS_ARM64 = Истина;
					КонецЕсли;
					
					Продолжить;
					
				КонецЕсли;
				
				Если ОперационнаяСистема = "linux" И ТипКомпоненты = "plugin" Тогда

					Если АрхитектураПлатформы = "i386" И ПрограммаПросмотра = "firefox" Тогда
						Реквизиты.Linux_x86_Firefox = Истина;
						Продолжить;
					КонецЕсли;

					Если АрхитектураПлатформы = "x86_64" И ПрограммаПросмотра = "firefox" Тогда
						Реквизиты.Linux_x86_64_Firefox = Истина;
						Продолжить;
					КонецЕсли;
					
					Если АрхитектураПлатформы = "arm64" И ПрограммаПросмотра = "firefox" Тогда
						Реквизиты.Linux_ARM64_Firefox = Истина;
						Продолжить;
					КонецЕсли;
					
					Если АрхитектураПлатформы = "e2k" И ПрограммаПросмотра = "firefox" Тогда
						Реквизиты.Linux_E2K_Firefox = Истина;
						Продолжить;
					КонецЕсли;
					
					Если АрхитектураПлатформы = "i386" И (ПрограммаПросмотра = "yandexbrowser" Или ПрограммаПросмотра = "anychromiumbased") Тогда
						Реквизиты.Linux_x86_ЯндексБраузер = Истина;
					КонецЕсли;
					
					Если АрхитектураПлатформы = "i386" И (ПрограммаПросмотра = "chrome" Или ПрограммаПросмотра = "anychromiumbased") Тогда
						Реквизиты.Linux_x86_Chrome = Истина;
					КонецЕсли;

					Если АрхитектураПлатформы = "x86_64" И (ПрограммаПросмотра = "yandexbrowser" Или ПрограммаПросмотра = "anychromiumbased") Тогда
						Реквизиты.Linux_x86_64_ЯндексБраузер = Истина;
					КонецЕсли;

					Если АрхитектураПлатформы = "x86_64" И (ПрограммаПросмотра = "chrome" Или ПрограммаПросмотра = "anychromiumbased") Тогда
						Реквизиты.Linux_x86_64_Chrome = Истина;
					КонецЕсли;
					
					Если АрхитектураПлатформы = "arm64" И (ПрограммаПросмотра = "yandexbrowser" Или ПрограммаПросмотра = "anychromiumbased") Тогда
						Реквизиты.Linux_ARM64_ЯндексБраузер = Истина;
					КонецЕсли;

					Если АрхитектураПлатформы = "arm64" И (ПрограммаПросмотра = "chrome" Или ПрограммаПросмотра = "anychromiumbased") Тогда
						Реквизиты.Linux_ARM64_Chrome = Истина;
					КонецЕсли;
					
					Если АрхитектураПлатформы = "e2k" И (ПрограммаПросмотра = "yandexbrowser" Или ПрограммаПросмотра = "anychromiumbased") Тогда
						Реквизиты.Linux_E2K_ЯндексБраузер = Истина;
					КонецЕсли;

					Если АрхитектураПлатформы = "e2k" И (ПрограммаПросмотра = "chrome" Или ПрограммаПросмотра = "anychromiumbased") Тогда
						Реквизиты.Linux_E2K_Chrome = Истина;
					КонецЕсли;
					
					Продолжить;
				КонецЕсли;
				
				Если ОперационнаяСистема = "windows" И ТипКомпоненты = "plugin" Тогда
					
					Если АрхитектураПлатформы = "i386" И ПрограммаПросмотра = "msie" Тогда
						Реквизиты.Windows_x86_MSIE = Истина;
						Продолжить;
					КонецЕсли;
	
					Если АрхитектураПлатформы = "x86_64" И ПрограммаПросмотра = "msie" Тогда
						Реквизиты.Windows_x86_64_MSIE = Истина;
						Продолжить;
					КонецЕсли;
					
					Если АрхитектураПлатформы = "i386" И ПрограммаПросмотра = "firefox" Тогда
						Реквизиты.Windows_x86_Firefox = Истина;
						Продолжить;
					КонецЕсли;
					
					Если АрхитектураПлатформы = "i386" И (ПрограммаПросмотра = "chrome" Или ПрограммаПросмотра = "anychromiumbased") Тогда
						Реквизиты.Windows_x86_Chrome = Истина;
					КонецЕсли;
					
					Если АрхитектураПлатформы = "i386" И (ПрограммаПросмотра = "yandexbrowser" Или ПрограммаПросмотра = "anychromiumbased") Тогда
						Реквизиты.Windows_x86_ЯндексБраузер = Истина;
					КонецЕсли;
					
					Если АрхитектураПлатформы = "x86_64" И (ПрограммаПросмотра = "yandexbrowser" Или ПрограммаПросмотра = "anychromiumbased") Тогда
						Реквизиты.Windows_x86_64_ЯндексБраузер = Истина;
					КонецЕсли;
		
					Продолжить;
					
				КонецЕсли;
				
				Если ОперационнаяСистема = "macos" И ТипКомпоненты = "plugin" Тогда

					Если  (АрхитектураПлатформы = "x86_64" Или АрхитектураПлатформы = "universal") И ПрограммаПросмотра = "safari" Тогда
						Реквизиты.MacOS_x86_64_Safari = Истина;
						Продолжить;
					КонецЕсли;
								
					Если (АрхитектураПлатформы = "x86_64" Или АрхитектураПлатформы = "universal") И ПрограммаПросмотра = "firefox" Тогда
						Реквизиты.MacOS_x86_64_Firefox = Истина;
						Продолжить;
					КонецЕсли;
					
					Если (АрхитектураПлатформы = "x86_64" Или АрхитектураПлатформы = "universal") И (ПрограммаПросмотра = "chrome" Или ПрограммаПросмотра = "anychromiumbased") Тогда
						Реквизиты.MacOS_x86_64_Chrome = Истина;
					КонецЕсли;
					
					Если (АрхитектураПлатформы = "x86_64" Или АрхитектураПлатформы = "universal") И (ПрограммаПросмотра = "yandexbrowser" 
							Или ПрограммаПросмотра = "anychromiumbased") Тогда
						Реквизиты.MacOS_x86_64_ЯндексБраузер = Истина;
					КонецЕсли;
				
					Продолжить;
					
				КонецЕсли;
				
			КонецЕсли;
		КонецЦикла;
	КонецЕсли;
	ЧтениеXML.Закрыть();

КонецПроцедуры

Процедура ЗаполнитьРеквизитыПоInfoXML(ИмяФайлаInfoXML, Реквизиты)

	ФайлПрочитан = Ложь;

	// Пытаемся разобрать по формату БПО.
	ЧтениеXML = Новый ЧтениеXML;
	ЧтениеXML.ОткрытьФайл(ИмяФайлаInfoXML);

	ЧтениеXML.ПерейтиКСодержимому();
	Если ЧтениеXML.Имя = "drivers" И ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
		Пока ЧтениеXML.Прочитать() Цикл
			Если ЧтениеXML.Имя = "component" И ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда

				Идентификатор = ЧтениеXML.ЗначениеАтрибута("progid");
				
				Реквизиты.Идентификатор = Сред(Идентификатор, СтрНайти(Идентификатор, ".") + 1);
				Реквизиты.Наименование = ЧтениеXML.ЗначениеАтрибута("name");
				Реквизиты.Версия = ЧтениеXML.ЗначениеАтрибута("version");

				ФайлПрочитан = Истина;

			КонецЕсли;
		КонецЦикла;
	КонецЕсли;
	ЧтениеXML.Закрыть();

	Если ФайлПрочитан Тогда
		Возврат;
	КонецЕсли;

	// Пытаемся разобрать по формату БЭД.
	ЧтениеXML = Новый ЧтениеXML;
	ЧтениеXML.ОткрытьФайл(ИмяФайлаInfoXML);

	ИнформацияКомпоненты = ФабрикаXDTO.ПрочитатьXML(ЧтениеXML);
	Реквизиты.Идентификатор = ИнформацияКомпоненты.progid;
	Реквизиты.Наименование = ИнформацияКомпоненты.name;
	Реквизиты.Версия = ИнформацияКомпоненты.version;

	ЧтениеXML.Закрыть();

КонецПроцедуры

Функция ВычислитьВыражениеXPath(Выражение, ДокументDOM)

	ЗначениеXPath = Неопределено;

	Разыменователь = ДокументDOM.СоздатьРазыменовательПИ();
	РезультатXPath = ДокументDOM.ВычислитьВыражениеXPath(Выражение, ДокументDOM, Разыменователь);

	УзелРезультата = РезультатXPath.ПолучитьСледующий();
	Если ТипЗнч(УзелРезультата) = Тип("АтрибутDOM") Тогда
		ЗначениеXPath = УзелРезультата.Значение;
	КонецЕсли;

	Возврат ЗначениеXPath
КонецФункции

Функция ДокументDOM(ПутьКФайлу)

	ЧтениеXML = Новый ЧтениеXML;
	ЧтениеXML.ОткрытьФайл(ПутьКФайлу);
	ПостроительDOM = Новый ПостроительDOM;
	ДокументDOM = ПостроительDOM.Прочитать(ЧтениеXML);
	ЧтениеXML.Закрыть();

	Возврат ДокументDOM;

КонецФункции

#КонецОбласти

#Область ЗагрузкаСПортала

Процедура ПроверитьДоступностьЗагрузкиСПортала()

	Если Не ДоступнаЗагрузкаСПортала() Тогда
		ВызватьИсключение НСтр("ru = 'Обновление внешних компонент с портала 1С:ИТС не доступно.'");
	КонецЕсли;

КонецПроцедуры

// Возвращаемое значение:
//  Структура:
//   * Идентификатор - Строка
//   * Версия - Строка
//   * ОбновлятьАвтоматически - Булево
//
Функция ПараметрыКомпонентаСПортала() Экспорт
	
	Результат = Новый Структура;
	Результат.Вставить("Идентификатор", "");
	Результат.Вставить("Версия", "");
	Результат.Вставить("ОбновлятьАвтоматически", Истина);
	Возврат Результат;
	
КонецФункции
	
// Параметры:
//  ПараметрыПроцедуры - см. ПараметрыКомпонентаСПортала.
//  АдресРезультата - Строка
//
Процедура НоваяКомпонентаСПортала(ПараметрыПроцедуры, АдресРезультата) Экспорт

	Если ОбщегоНазначения.ПодсистемаСуществует("ИнтернетПоддержкаПользователей.ПолучениеВнешнихКомпонент") Тогда

		Идентификатор = ПараметрыПроцедуры.Идентификатор;
		Версия = ПараметрыПроцедуры.Версия;

		ПроверитьДоступностьЗагрузкиСПортала();

		МодульПолучениеВнешнихКомпонент = ОбщегоНазначения.ОбщийМодуль("ПолучениеВнешнихКомпонент");

		ОписаниеВнешнихКомпонент = МодульПолучениеВнешнихКомпонент.ОписаниеВнешнихКомпонент();
		ОписаниеВнешнейКомпоненты = ОписаниеВнешнихКомпонент.Добавить();
		ОписаниеВнешнейКомпоненты.Идентификатор = Идентификатор;
		ОписаниеВнешнейКомпоненты.Версия = Версия;

		Если Не ЗначениеЗаполнено(Версия) Тогда
			РезультатОперации = МодульПолучениеВнешнихКомпонент.АктуальныеВерсииВнешнихКомпонент(ОписаниеВнешнихКомпонент);
		Иначе
			РезультатОперации = МодульПолучениеВнешнихКомпонент.ВерсииВнешнихКомпонент(ОписаниеВнешнихКомпонент);
		КонецЕсли;

		Если ЗначениеЗаполнено(РезультатОперации.КодОшибки) Тогда
			ТекстИсключения = ?(Пользователи.ЭтоПолноправныйПользователь(), РезультатОперации.ИнформацияОбОшибке, РезультатОперации.СообщениеОбОшибке);
			ВызватьИсключение ТекстИсключения;
		КонецЕсли;

		Если РезультатОперации.ДанныеВнешнихКомпонент.Количество() = 0 Тогда
			ТекстИсключения = НСтр("ru = 'На портале 1С:ИТС внешняя компонента отсутствует.'");
			ЗаписьЖурналаРегистрации(НСтр("ru = 'Обновление внешних компонент'", ОбщегоНазначения.КодОсновногоЯзыка()), УровеньЖурналаРегистрации.Ошибка, , , ТекстИсключения);
			ВызватьИсключение ТекстИсключения;
		КонецЕсли;

		СтрокаРезультата = РезультатОперации.ДанныеВнешнихКомпонент[0];
		КодОшибки = СтрокаРезультата.КодОшибки;

		Если ЗначениеЗаполнено(КодОшибки) Тогда

			ИнформацияОбОшибке = "";
			Если КодОшибки = "ОтсутствуетКомпонента" Тогда
				ИнформацияОбОшибке = НСтр("ru = 'На портале 1С:ИТС нет требуемой внешней компоненты %1.'");
			ИначеЕсли КодОшибки = "ОтсутствуетВерсия" Тогда
				ИнформацияОбОшибке = НСтр("ru = 'На портале 1С:ИТС нет требуемой версии внешней компоненты %1.'");
			ИначеЕсли КодОшибки = "ФайлНеЗагружен" Или КодОшибки = "АктуальнаяВерсия" Тогда
				ИнформацияОбОшибке = НСтр("ru = 'Не удалось загрузить внешнюю компоненту %1 по непредвиденной причине (код %2).'");
			КонецЕсли;

			ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ИнформацияОбОшибке, 
				ПредставлениеКомпоненты(Идентификатор, Версия), КодОшибки);
			ЗаписьЖурналаРегистрации(НСтр("ru = 'Обновление внешних компонент'", ОбщегоНазначения.КодОсновногоЯзыка()), 
				УровеньЖурналаРегистрации.Ошибка, , , ТекстОшибки);
			ВызватьИсключение ТекстОшибки;
		КонецЕсли;

		ДвоичныеДанные = ПолучитьИзВременногоХранилища(СтрокаРезультата.АдресФайла);
		Информация = ИнформацияОКомпонентеИзФайла(ДвоичныеДанные, Ложь);

		Если Не Информация.Разобрано Тогда
			
			ТекстИсключения = Информация.ОписаниеОшибки + ?(Информация.ИнформацияОбОшибке = Неопределено, "",
			 ": " + ОбработкаОшибок.КраткоеПредставлениеОшибки(Информация.ИнформацияОбОшибке));
				
			ЗаписьЖурналаРегистрации(НСтр("ru = 'Обновление внешних компонент'", ОбщегоНазначения.КодОсновногоЯзыка()), 
				УровеньЖурналаРегистрации.Ошибка, , , ТекстИсключения);
			ВызватьИсключение ТекстИсключения;
		КонецЕсли;

		УстановитьПривилегированныйРежим(Истина);

		НачатьТранзакцию();
		Попытка
			// Создание экземпляра компоненты.
			Объект = Справочники.ВнешниеКомпоненты.СоздатьЭлемент();
			Объект.Заполнить(Неопределено); // Конструктор по умолчанию.
			ЗаполнитьЗначенияСвойств(Объект, Информация.Реквизиты); // По данным манифеста.
			ЗаполнитьЗначенияСвойств(Объект, СтрокаРезультата); // По данным с сайта.
			Объект.ОписаниеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Загружена с Портала 1С:ИТС. %1.'"), ТекущаяДатаСеанса());
			Объект.ЦелевыеПлатформы = Новый ХранилищеЗначения(Информация.Реквизиты.ЦелевыеПлатформы);
			Объект.ДополнительныеСвойства.Вставить("ДвоичныеДанныеКомпоненты", Информация.ДвоичныеДанные);

			Если Не ЗначениеЗаполнено(Версия) Тогда // Если запрос конкретной версии - пропускаем.
				Объект.ОбновлятьСПортала1СИТС = Объект.ЭтоКомпонентаПоследнейВерсии()
					И ПараметрыПроцедуры.ОбновлятьАвтоматически;
			КонецЕсли;

			Объект.Записать();
			ЗафиксироватьТранзакцию();
		Исключение
			ОтменитьТранзакцию();
			ЗаписьЖурналаРегистрации(НСтр("ru = 'Обновление внешних компонент'", ОбщегоНазначения.КодОсновногоЯзыка()), УровеньЖурналаРегистрации.Ошибка, , , ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
			ВызватьИсключение;
		КонецПопытки;
		ОповеститьВсеСеансыОбИзмененииВнешнейКомпоненты();
	Иначе
		ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Действие недоступно, т.к. отсутствует подсистема ""%1"".'"),
			"ИнтернетПоддержкаПользователей.ПолучениеВнешнихКомпонент");
	КонецЕсли;

КонецПроцедуры

// Возвращаемое значение:
//   Структура:
//     * ОбновляемыеКомпоненты - Массив из СправочникСсылка.ВнешниеКомпоненты 
//  
Функция ПараметрыОбновленияКомпонентСПортала() Экспорт
	
	Результат = Новый Структура;
	Результат.Вставить("ОбновляемыеКомпоненты", Новый Массив);
	Возврат Результат;
	
КонецФункции

// Параметры:
//  ПараметрыПроцедуры - см. ПараметрыОбновленияКомпонентСПортала
//  АдресРезультата - Строка
//
Процедура ОбновитьКомпонентыСПортала(ПараметрыПроцедуры, АдресРезультата) Экспорт

	Если ОбщегоНазначения.ПодсистемаСуществует("ИнтернетПоддержкаПользователей.ПолучениеВнешнихКомпонент") Тогда

		ПроверитьДоступностьЗагрузкиСПортала();

		МодульПолучениеВнешнихКомпонент = ОбщегоНазначения.ОбщийМодуль("ПолучениеВнешнихКомпонент");
		ОписаниеВнешнихКомпонент = МодульПолучениеВнешнихКомпонент.ОписаниеВнешнихКомпонент();

		ОбновляемыеКомпоненты = ПараметрыПроцедуры.ОбновляемыеКомпоненты;
		Реквизиты = ОбщегоНазначения.ЗначенияРеквизитовОбъектов(ОбновляемыеКомпоненты, "Идентификатор, Версия");
		Для Каждого ОбновляемаяКомпонента Из ОбновляемыеКомпоненты Цикл
			ОписаниеКомпоненты = ОписаниеВнешнихКомпонент.Добавить();
			ОписаниеКомпоненты.Идентификатор = Реквизиты[ОбновляемаяКомпонента].Идентификатор;
			ОписаниеКомпоненты.Версия = Реквизиты[ОбновляемаяКомпонента].Версия;
		КонецЦикла;

		РезультатОперации = МодульПолучениеВнешнихКомпонент.АктуальныеВерсииВнешнихКомпонент(ОписаниеВнешнихКомпонент);
		Если ЗначениеЗаполнено(РезультатОперации.КодОшибки) Тогда
			ТекстИсключения = ?(Пользователи.ЭтоПолноправныйПользователь(), РезультатОперации.ИнформацияОбОшибке, РезультатОперации.СообщениеОбОшибке);
			ВызватьИсключение ТекстИсключения;
		КонецЕсли;

		ВнешниеКомпонентыСервер.ОбновитьВнешниеКомпоненты(РезультатОперации.ДанныеВнешнихКомпонент, АдресРезультата);
		ОповеститьВсеСеансыОбИзмененииВнешнейКомпоненты();
	Иначе
		ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Действие недоступно, т.к. отсутствует подсистема ""%1"".'"),
			"ИнтернетПоддержкаПользователей.ПолучениеВнешнихКомпонент");
	КонецЕсли;

КонецПроцедуры

#КонецОбласти

#КонецОбласти